home *** CD-ROM | disk | FTP | other *** search
- <?php
- // vim: set et ts=4 sw=4 fdm=marker:
- // +----------------------------------------------------------------------+
- // | PHP Version 4 |
- // +----------------------------------------------------------------------+
- // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, |
- // | Stig. S. Bakken, Lukas Smith |
- // | All rights reserved. |
- // +----------------------------------------------------------------------+
- // | MDB is a merge of PEAR DB and Metabases that provides a unified DB |
- // | API as well as database abstraction for PHP applications. |
- // | This LICENSE is in the BSD license style. |
- // | |
- // | Redistribution and use in source and binary forms, with or without |
- // | modification, are permitted provided that the following conditions |
- // | are met: |
- // | |
- // | Redistributions of source code must retain the above copyright |
- // | notice, this list of conditions and the following disclaimer. |
- // | |
- // | Redistributions in binary form must reproduce the above copyright |
- // | notice, this list of conditions and the following disclaimer in the |
- // | documentation and/or other materials provided with the distribution. |
- // | |
- // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
- // | Lukas Smith nor the names of his contributors may be used to endorse |
- // | or promote products derived from this software without specific prior|
- // | written permission. |
- // | |
- // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
- // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
- // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
- // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
- // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
- // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
- // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
- // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
- // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
- // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
- // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
- // | POSSIBILITY OF SUCH DAMAGE. |
- // +----------------------------------------------------------------------+
- // | Author: Lukas Smith <smith@backendmedia.com> |
- // +----------------------------------------------------------------------+
- //
- // $Id: mysql.php,v 1.80.4.8 2004/01/08 13:43:02 lsmith Exp $
- //
-
- require_once('MDB/Common.php');
-
- /**
- * MDB MySQL driver
- *
- * Notes:
- * - The decimal type fields are emulated with integer fields.
- *
- * @package MDB
- * @category Database
- * @author Lukas Smith <smith@backendmedia.com>
- */
- class MDB_mysql extends MDB_Common
- {
- // {{{ properties
-
- var $connection = 0;
- var $connected_host;
- var $connected_user;
- var $connected_password;
- var $connected_port;
- var $opened_persistent = '';
-
- var $escape_quotes = "\\";
- var $decimal_factor = 1.0;
-
- var $highest_fetched_row = array();
- var $columns = array();
-
- // MySQL specific class variable
- var $default_table_type = '';
- var $fixed_float = 0;
- var $dummy_primary_key = 'dummy_primary_key';
-
- // }}}
- // {{{ constructor
-
- /**
- * Constructor
- */
- function MDB_mysql()
- {
- $this->MDB_Common();
- $this->phptype = 'mysql';
- $this->dbsyntax = 'mysql';
-
- $this->supported['Sequences'] = 1;
- $this->supported['Indexes'] = 1;
- $this->supported['AffectedRows'] = 1;
- $this->supported['Summaryfunctions'] = 1;
- $this->supported['OrderByText'] = 1;
- $this->supported['CurrId'] = 1;
- $this->supported['SelectRowRanges'] = 1;
- $this->supported['LOBs'] = 1;
- $this->supported['Replace'] = 1;
- $this->supported['SubSelects'] = 0;
- $this->supported['Transactions'] = 0;
-
- $this->decimal_factor = pow(10.0, $this->decimal_places);
-
- $this->options['DefaultTableType'] = FALSE;
- $this->options['fixed_float'] = FALSE;
-
- $this->errorcode_map = array(
- 1004 => MDB_ERROR_CANNOT_CREATE,
- 1005 => MDB_ERROR_CANNOT_CREATE,
- 1006 => MDB_ERROR_CANNOT_CREATE,
- 1007 => MDB_ERROR_ALREADY_EXISTS,
- 1008 => MDB_ERROR_CANNOT_DROP,
- 1022 => MDB_ERROR_ALREADY_EXISTS,
- 1046 => MDB_ERROR_NODBSELECTED,
- 1050 => MDB_ERROR_ALREADY_EXISTS,
- 1051 => MDB_ERROR_NOSUCHTABLE,
- 1054 => MDB_ERROR_NOSUCHFIELD,
- 1062 => MDB_ERROR_ALREADY_EXISTS,
- 1064 => MDB_ERROR_SYNTAX,
- 1100 => MDB_ERROR_NOT_LOCKED,
- 1136 => MDB_ERROR_VALUE_COUNT_ON_ROW,
- 1146 => MDB_ERROR_NOSUCHTABLE,
- 1048 => MDB_ERROR_CONSTRAINT,
- 1216 => MDB_ERROR_CONSTRAINT,
- );
- }
-
- // }}}
- // {{{ errorNative()
-
- /**
- * Get the native error code of the last error (if any) that
- * occured on the current connection.
- *
- * @access public
- *
- * @return int native MySQL error code
- */
- function errorNative()
- {
- return mysql_errno($this->connection);
- }
-
- // }}}
- // {{{ mysqlRaiseError()
-
- /**
- * This method is used to communicate an error and invoke error
- * callbacks etc. Basically a wrapper for MDB::raiseError
- * that checks for native error msgs.
- *
- * @param integer $errno error code
- * @return object a PEAR error object
- * @access public
- * @see PEAR_Error
- */
- function mysqlRaiseError($errno = NULL)
- {
- if ($errno == NULL) {
- $errno = $this->errorCode(mysql_errno($this->connection));
- }
- return($this->raiseError($errno, NULL, NULL, NULL, @mysql_error($this->connection)));
- }
-
- // }}}
- // {{{ autoCommit()
-
- /**
- * Define whether database changes done on the database be automatically
- * committed. This function may also implicitly start or end a transaction.
- *
- * @param boolean $auto_commit flag that indicates whether the database
- * changes should be committed right after
- * executing every query statement. If this
- * argument is 0 a transaction implicitly
- * started. Otherwise, if a transaction is
- * in progress it is ended by committing any
- * database changes that were pending.
- *
- * @access public
- *
- * @return mixed MDB_OK on success, a MDB error on failure
- */
- function autoCommit($auto_commit)
- {
- $this->debug("AutoCommit: ".($auto_commit ? "On" : "Off"));
- if (!isset($this->supported['Transactions'])) {
- return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL,
- 'Auto-commit transactions: transactions are not in use'));
- }
- if ($this->auto_commit == $auto_commit) {
- return(MDB_OK);
- }
- if ($this->connection) {
- if ($auto_commit) {
- $result = $this->query('COMMIT');
- if (MDB::isError($result)) {
- return($result);
- }
- $result = $this->query('SET AUTOCOMMIT = 1');
- if (MDB::isError($result)) {
- return($result);
- }
- } else {
- $result = $this->query('SET AUTOCOMMIT = 0');
- if (MDB::isError($result)) {
- return($result);
- }
- }
- }
- $this->auto_commit = $auto_commit;
- $this->in_transaction = !$auto_commit;
- return(MDB_OK);
- }
-
- // }}}
- // {{{ commit()
-
- /**
- * Commit the database changes done during a transaction that is in
- * progress. This function may only be called when auto-committing is
- * disabled, otherwise it will fail. Therefore, a new transaction is
- * implicitly started after committing the pending changes.
- *
- * @access public
- *
- * @return mixed MDB_OK on success, a MDB error on failure
- */
- function commit()
- {
- $this->debug("Commit Transaction");
- if (!isset($this->supported['Transactions'])) {
- return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL,
- 'Commit transactions: transactions are not in use'));
- }
- if ($this->auto_commit) {
- return($this->raiseError(MDB_ERROR, NULL, NULL,
- 'Commit transactions: transaction changes are being auto commited'));
- }
- return($this->query('COMMIT'));
- }
-
- // }}}
- // {{{ rollback()
-
- /**
- * Cancel any database changes done during a transaction that is in
- * progress. This function may only be called when auto-committing is
- * disabled, otherwise it will fail. Therefore, a new transaction is
- * implicitly started after canceling the pending changes.
- *
- * @access public
- *
- * @return mixed MDB_OK on success, a MDB error on failure
- */
- function rollback()
- {
- $this->debug("Rollback Transaction");
- if (!isset($this->supported['Transactions'])) {
- return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL,
- 'Rollback transactions: transactions are not in use'));
- }
- if ($this->auto_commit) {
- return($this->raiseError(MDB_ERROR, NULL, NULL,
- 'Rollback transactions: transactions can not be rolled back when changes are auto commited'));
- }
- return($this->query('ROLLBACK'));
- }
-
- // }}}
- // {{{ connect()
-
- /**
- * Connect to the database
- *
- * @return TRUE on success, MDB_Error on failure
- **/
- function connect()
- {
- $port = (isset($this->port) ? $this->port : '');
- if($this->connection != 0) {
- if (!strcmp($this->connected_host, $this->host)
- && !strcmp($this->connected_user, $this->user)
- && !strcmp($this->connected_password, $this->password)
- && !strcmp($this->connected_port, $port)
- && $this->opened_persistent == $this->options['persistent'])
- {
- return(MDB_OK);
- }
- mysql_close($this->connection);
- $this->connection = 0;
- $this->affected_rows = -1;
- }
-
- if(!PEAR::loadExtension($this->phptype)) {
- return(PEAR::raiseError(NULL, MDB_ERROR_NOT_FOUND,
- NULL, NULL, 'extension '.$this->phptype.' is not compiled into PHP',
- 'MDB_Error', TRUE));
- }
- $UseTransactions = $this->getOption('UseTransactions');
- if(!MDB::isError($UseTransactions) && $UseTransactions) {
- $this->supported['Transactions'] = 1;
- $this->default_table_type = 'BDB';
- } else {
- $this->supported['Transactions'] = 0;
- $this->default_table_type = '';
- }
- $DefaultTableType = $this->getOption('DefaultTableType');
- if(!MDB::isError($DefaultTableType) && $DefaultTableType) {
- switch($this->default_table_type = strtoupper($DefaultTableType)) {
- case 'BERKELEYDB':
- $this->default_table_type = 'BDB';
- case 'BDB':
- case 'INNODB':
- case 'GEMINI':
- break;
- case 'HEAP':
- case 'ISAM':
- case 'MERGE':
- case 'MRG_MYISAM':
- case 'MYISAM':
- if(isset($this->supported['Transactions'])) {
- $this->warnings[] = $DefaultTableType
- .' is not a transaction-safe default table type';
- }
- break;
- default:
- $this->warnings[] = $DefaultTableType
- .' is not a supported default table type';
- }
- }
-
- $this->fixed_float = 30;
- $function = ($this->options['persistent'] ? 'mysql_pconnect' : 'mysql_connect');
- if (!function_exists($function)) {
- return($this->raiseError(MDB_ERROR_UNSUPPORTED));
- }
-
- @ini_set('track_errors', TRUE);
- $this->connection = @$function(
- $this->host.(!strcmp($port,'') ? '' : ':'.$port),
- $this->user, $this->password);
- @ini_restore('track_errors');
- if ($this->connection <= 0) {
- return($this->raiseError(MDB_ERROR_CONNECT_FAILED, NULL, NULL,
- $php_errormsg));
- }
-
- if (isset($this->options['fixedfloat'])) {
- $this->fixed_float = $this->options['fixedfloat'];
- } else {
- if (($result = mysql_query('SELECT VERSION()', $this->connection))) {
- $version = explode('.', mysql_result($result,0,0));
- $major = intval($version[0]);
- $minor = intval($version[1]);
- $revision = intval($version[2]);
- if ($major > 3 || ($major == 3 && $minor >= 23
- && ($minor > 23 || $revision >= 6)))
- {
- $this->fixed_float = 0;
- }
- mysql_free_result($result);
- }
- }
- if (isset($this->supported['Transactions']) && !$this->auto_commit) {
- if (!mysql_query('SET AUTOCOMMIT = 0', $this->connection)) {
- mysql_close($this->connection);
- $this->connection = 0;
- $this->affected_rows = -1;
- return($this->raiseError());
- }
- $this->in_transaction = TRUE;
- }
- $this->connected_host = $this->host;
- $this->connected_user = $this->user;
- $this->connected_password = $this->password;
- $this->connected_port = $port;
- $this->opened_persistent = $this->getoption('persistent');
- return(MDB_OK);
- }
-
- // }}}
- // {{{ _close()
- /**
- * all the RDBMS specific things needed close a DB connection
- *
- * @return boolean
- * @access private
- **/
- function _close()
- {
- if ($this->connection != 0) {
- if (isset($this->supported['Transactions']) && !$this->auto_commit) {
- $result = $this->autoCommit(TRUE);
- }
- mysql_close($this->connection);
- $this->connection = 0;
- $this->affected_rows = -1;
-
- if (isset($result) && MDB::isError($result)) {
- return($result);
- }
- unset($GLOBALS['_MDB_databases'][$this->database]);
- return(TRUE);
- }
- return(FALSE);
- }
-
- // }}}
- // {{{ query()
-
- /**
- * Send a query to the database and return any results
- *
- * @access public
- *
- * @param string $query the SQL query
- * @param mixed $types array that contains the types of the columns in
- * the result set
- *
- * @return mixed a result handle or MDB_OK on success, a MDB error on failure
- */
- function query($query, $types = NULL)
- {
- $this->debug("Query: $query");
- $ismanip = MDB::isManip($query);
- $this->last_query = $query;
- $first = $this->first_selected_row;
- $limit = $this->selected_row_limit;
- $this->first_selected_row = $this->selected_row_limit = 0;
-
- $result = $this->connect();
- if (MDB::isError($result)) {
- return($result);
- }
- if($limit > 0) {
- if ($ismanip) {
- $query .= " LIMIT $limit";
- } else {
- $query .= " LIMIT $first,$limit";
- }
- }
- if ($this->database_name) {
- if(!mysql_select_db($this->database_name, $this->connection)) {
- return($this->mysqlRaiseError());
- }
- }
- if ($result = mysql_query($query, $this->connection)) {
- if ($ismanip) {
- $this->affected_rows = mysql_affected_rows($this->connection);
- return(MDB_OK);
- } else {
- $this->highest_fetched_row[$result] = -1;
- if ($types != NULL) {
- if (!is_array($types)) {
- $types = array($types);
- }
- if (MDB::isError($err = $this->setResultTypes($result, $types))) {
- $this->freeResult($result);
- return($err);
- }
- }
- return($result);
- }
- }
- return($this->mysqlRaiseError());
- }
-
- // }}}
- // {{{ subSelect()
-
- /**
- * simple subselect emulation for Mysql
- *
- * @access public
- *
- * @param string $query the SQL query for the subselect that may only
- * return a column
- * @param string $quote determines if the data needs to be quoted before
- * being returned
- *
- * @return string the query
- */
- function subSelect($query, $quote = FALSE)
- {
- if($this->supported['SubSelects'] == 1) {
- return($query);
- }
- $col = $this->queryCol($query);
- if (MDB::isError($col)) {
- return($col);
- }
- if(!is_array($col) || count($col) == 0) {
- return 'NULL';
- }
- if($quote) {
- for($i = 0, $j = count($col); $i < $j; ++$i) {
- $col[$i] = $this->getTextValue($col[$i]);
- }
- }
- return(implode(', ', $col));
- }
-
- // }}}
- // {{{ replace()
-
- /**
- * Execute a SQL REPLACE query. A REPLACE query is identical to a INSERT
- * query, except that if there is already a row in the table with the same
- * key field values, the REPLACE query just updates its values instead of
- * inserting a new row.
- *
- * The REPLACE type of query does not make part of the SQL standards. Since
- * practically only MySQL implements it natively, this type of query is
- * emulated through this method for other DBMS using standard types of
- * queries inside a transaction to assure the atomicity of the operation.
- *
- * @access public
- *
- * @param string $table name of the table on which the REPLACE query will
- * be executed.
- * @param array $fields associative array that describes the fields and the
- * values that will be inserted or updated in the specified table. The
- * indexes of the array are the names of all the fields of the table. The
- * values of the array are also associative arrays that describe the
- * values and other properties of the table fields.
- *
- * Here follows a list of field properties that need to be specified:
- *
- * Value:
- * Value to be assigned to the specified field. This value may be
- * of specified in database independent type format as this
- * function can perform the necessary datatype conversions.
- *
- * Default:
- * this property is required unless the Null property
- * is set to 1.
- *
- * Type
- * Name of the type of the field. Currently, all types Metabase
- * are supported except for clob and blob.
- *
- * Default: no type conversion
- *
- * Null
- * Boolean property that indicates that the value for this field
- * should be set to NULL.
- *
- * The default value for fields missing in INSERT queries may be
- * specified the definition of a table. Often, the default value
- * is already NULL, but since the REPLACE may be emulated using
- * an UPDATE query, make sure that all fields of the table are
- * listed in this function argument array.
- *
- * Default: 0
- *
- * Key
- * Boolean property that indicates that this field should be
- * handled as a primary key or at least as part of the compound
- * unique index of the table that will determine the row that will
- * updated if it exists or inserted a new row otherwise.
- *
- * This function will fail if no key field is specified or if the
- * value of a key field is set to NULL because fields that are
- * part of unique index they may not be NULL.
- *
- * Default: 0
- *
- * @return mixed MDB_OK on success, a MDB error on failure
- */
- function replace($table, $fields)
- {
- $count = count($fields);
- for($keys = 0, $query = $values = '',reset($fields), $field = 0;
- $field<$count;
- next($fields), $field++)
- {
- $name = key($fields);
- if ($field > 0) {
- $query .= ',';
- $values .= ',';
- }
- $query .= $name;
- if (isset($fields[$name]['Null']) && $fields[$name]['Null']) {
- $value = 'NULL';
- } else {
- if(isset($fields[$name]['Type'])) {
- switch ($fields[$name]['Type']) {
- case 'text':
- $value = $this->getTextValue($fields[$name]['Value']);
- break;
- case 'boolean':
- $value = $this->getBooleanValue($fields[$name]['Value']);
- break;
- case 'integer':
- $value = $this->getIntegerValue($fields[$name]['Value']);
- break;
- case 'decimal':
- $value = $this->getDecimalValue($fields[$name]['Value']);
- break;
- case 'float':
- $value = $this->getFloatValue($fields[$name]['Value']);
- break;
- case 'date':
- $value = $this->getDateValue($fields[$name]['Value']);
- break;
- case 'time':
- $value = $this->getTimeValue($fields[$name]['Value']);
- break;
- case 'timestamp':
- $value = $this->getTimestampValue($fields[$name]['Value']);
- break;
- default:
- return($this->raiseError(MDB_ERROR_CANNOT_REPLACE, NULL, NULL,
- 'no supported type for field "' . $name . '" specified'));
- }
- } else {
- $value = $fields[$name]['Value'];
- }
- }
- $values .= $value;
- if (isset($fields[$name]['Key']) && $fields[$name]['Key']) {
- if ($value === 'NULL') {
- return($this->raiseError(MDB_ERROR_CANNOT_REPLACE, NULL, NULL,
- $name.': key values may not be NULL'));
- }
- $keys++;
- }
- }
- if ($keys == 0) {
- return($this->raiseError(MDB_ERROR_CANNOT_REPLACE, NULL, NULL,
- 'not specified which fields are keys'));
- }
- return($this->query("REPLACE INTO $table ($query) VALUES ($values)"));
- }
-
- // }}}
- // {{{ getColumnNames()
-
- /**
- * Retrieve the names of columns returned by the DBMS in a query result.
- *
- * @param resource $result result identifier
- * @return mixed an associative array variable
- * that will hold the names of columns. The
- * indexes of the array are the column names
- * mapped to lower case and the values are the
- * respective numbers of the columns starting
- * from 0. Some DBMS may not return any
- * columns when the result set does not
- * contain any rows.
- *
- * a MDB error on failure
- * @access public
- */
- function getColumnNames($result)
- {
- $result_value = intval($result);
- if (!isset($this->highest_fetched_row[$result_value])) {
- return($this->raiseError(MDB_ERROR_INVALID, NULL, NULL,
- 'Get column names: it was specified an inexisting result set'));
- }
- if (!isset($this->columns[$result_value])) {
- $this->columns[$result_value] = array();
- $columns = mysql_num_fields($result);
- for($column = 0; $column < $columns; $column++) {
- $this->columns[$result_value][strtolower(mysql_field_name($result, $column))] = $column;
- }
- }
- return($this->columns[$result_value]);
- }
-
- // }}}
- // {{{ numCols()
-
- /**
- * Count the number of columns returned by the DBMS in a query result.
- *
- * @param resource $result result identifier
- * @access public
- * @return mixed integer value with the number of columns, a MDB error
- * on failure
- */
- function numCols($result)
- {
- if (!isset($this->highest_fetched_row[intval($result)])) {
- return($this->raiseError(MDB_ERROR_INVALID, NULL, NULL,
- 'numCols: it was specified an inexisting result set'));
- }
- return(mysql_num_fields($result));
- }
-
- // }}}
- // {{{ endOfResult()
-
- /**
- * check if the end of the result set has been reached
- *
- * @param resource $result result identifier
- * @return mixed TRUE or FALSE on sucess, a MDB error on failure
- * @access public
- */
- function endOfResult($result)
- {
- if (!isset($this->highest_fetched_row[$result])) {
- return($this->raiseError(MDB_ERROR, NULL, NULL,
- 'End of result: attempted to check the end of an unknown result'));
- }
- return($this->highest_fetched_row[$result] >= $this->numRows($result)-1);
- }
-
- // }}}
- // {{{ fetch()
-
- /**
- * fetch value from a result set
- *
- * @param resource $result result identifier
- * @param int $row number of the row where the data can be found
- * @param int $field field number where the data can be found
- * @return mixed string on success, a MDB error on failure
- * @access public
- */
- function fetch($result, $row, $field)
- {
- $this->highest_fetched_row[$result] =
- max($this->highest_fetched_row[$result], $row);
- $res = @mysql_result($result, $row, $field);
- if ($res === FALSE && $res != NULL) {
- return($this->mysqlRaiseError($errno));
- }
- return($res);
- }
-
- // }}}
- // {{{ fetchClob()
-
- /**
- * fetch a clob value from a result set
- *
- * @param resource $result result identifier
- * @param int $row number of the row where the data can be found
- * @param int $field field number where the data can be found
- * @return mixed content of the specified data cell, a MDB error on failure,
- * a MDB error on failure
- * @access public
- */
- function fetchClob($result, $row, $field)
- {
- return($this->fetchLob($result, $row, $field));
- }
-
- // }}}
- // {{{ fetchBlob()
-
- /**
- * fetch a blob value from a result set
- *
- * @param resource $result result identifier
- * @param int $row number of the row where the data can be found
- * @param int $field field number where the data can be found
- * @return mixed content of the specified data cell, a MDB error on failure
- * @access public
- */
- function fetchBlob($result, $row, $field)
- {
- return($this->fetchLob($result, $row, $field));
- }
-
- // }}}
- // {{{ convertResult()
-
- /**
- * convert a value to a RDBMS indepdenant MDB type
- *
- * @param mixed $value value to be converted
- * @param int $type constant that specifies which type to convert to
- * @return mixed converted value
- * @access public
- */
- function convertResult($value, $type)
- {
- switch($type) {
- case MDB_TYPE_DECIMAL:
- return(sprintf('%.'.$this->decimal_places.'f', doubleval($value)/$this->decimal_factor));
- default:
- return($this->_baseConvertResult($value, $type));
- }
- }
-
- // }}}
- // {{{ numRows()
-
- /**
- * returns the number of rows in a result object
- *
- * @param ressource $result a valid result ressouce pointer
- * @return mixed MDB_Error or the number of rows
- * @access public
- */
- function numRows($result)
- {
- return(mysql_num_rows($result));
- }
-
- // }}}
- // {{{ freeResult()
-
- /**
- * Free the internal resources associated with $result.
- *
- * @param $result result identifier
- * @return boolean TRUE on success, FALSE if $result is invalid
- * @access public
- */
- function freeResult($result)
- {
- if(isset($this->highest_fetched_row[$result])) {
- unset($this->highest_fetched_row[$result]);
- }
- if(isset($this->columns[$result])) {
- unset($this->columns[$result]);
- }
- if(isset($this->result_types[$result])) {
- unset($this->result_types[$result]);
- }
- return(mysql_free_result($result));
- }
-
- // }}}
- // {{{ getIntegerDeclaration()
-
- /**
- * Obtain DBMS specific SQL code portion needed to declare an integer type
- * field to be used in statements like CREATE TABLE.
- *
- * @param string $name name the field to be declared.
- * @param string $field associative array with the name of the properties
- * of the field being declared as array indexes.
- * Currently, the types of supported field
- * properties are as follows:
- *
- * unsigned
- * Boolean flag that indicates whether the field
- * should be declared as unsigned integer if
- * possible.
- *
- * default
- * Integer value to be used as default for this
- * field.
- *
- * notnull
- * Boolean flag that indicates whether this field is
- * constrained to not be set to NULL.
- * @return string DBMS specific SQL code portion that should be used to
- * declare the specified field.
- * @access public
- */
- function getIntegerDeclaration($name, $field)
- {
- return("$name INT".
- (isset($field['unsigned']) ? ' UNSIGNED' : '').
- (isset($field['default']) ? ' DEFAULT '.$field['default'] : '').
- (isset($field['notnull']) ? ' NOT NULL' : '')
- );
- }
-
- // }}}
- // {{{ getClobDeclaration()
-
- /**
- * Obtain DBMS specific SQL code portion needed to declare an character
- * large object type field to be used in statements like CREATE TABLE.
- *
- * @param string $name name the field to be declared.
- * @param string $field associative array with the name of the
- * properties of the field being declared as array
- * indexes. Currently, the types of supported field
- * properties are as follows:
- *
- * length
- * Integer value that determines the maximum length
- * of the large object field. If this argument is
- * missing the field should be declared to have the
- * longest length allowed by the DBMS.
- *
- * notnull
- * Boolean flag that indicates whether this field
- * is constrained to not be set to NULL.
- * @return string DBMS specific SQL code portion that should be used to
- * declare the specified field.
- * @access public
- */
- function getClobDeclaration($name, $field)
- {
- if (isset($field['length'])) {
- $length = $field['length'];
- if ($length <= 255) {
- $type = 'TINYTEXT';
- } else {
- if ($length <= 65535) {
- $type = 'TEXT';
- } else {
- if ($length <= 16777215) {
- $type = 'MEDIUMTEXT';
- } else {
- $type = 'LONGTEXT';
- }
- }
- }
- } else {
- $type = 'LONGTEXT';
- }
- return("$name $type".
- (isset($field['notnull']) ? ' NOT NULL' : ''));
- }
-
- // }}}
- // {{{ getBlobDeclaration()
-
- /**
- * Obtain DBMS specific SQL code portion needed to declare an binary large
- * object type field to be used in statements like CREATE TABLE.
- *
- * @param string $name name the field to be declared.
- * @param string $field associative array with the name of the properties
- * of the field being declared as array indexes.
- * Currently, the types of supported field
- * properties are as follows:
- *
- * length
- * Integer value that determines the maximum length
- * of the large object field. If this argument is
- * missing the field should be declared to have the
- * longest length allowed by the DBMS.
- *
- * notnull
- * Boolean flag that indicates whether this field is
- * constrained to not be set to NULL.
- * @return string DBMS specific SQL code portion that should be used to
- * declare the specified field.
- * @access public
- */
- function getBlobDeclaration($name, $field)
- {
- if (isset($field['length'])) {
- $length = $field['length'];
- if ($length <= 255) {
- $type = 'TINYBLOB';
- } else {
- if ($length <= 65535) {
- $type = 'BLOB';
- } else {
- if ($length <= 16777215) {
- $type = 'MEDIUMBLOB';
- } else {
- $type = 'LONGBLOB';
- }
- }
- }
- }
- else {
- $type = 'LONGBLOB';
- }
- return("$name $type".
- (isset($field['notnull']) ? ' NOT NULL' : ''));
- }
-
- // }}}
- // {{{ getDateDeclaration()
-
- /**
- * Obtain DBMS specific SQL code portion needed to declare an date type
- * field to be used in statements like CREATE TABLE.
- *
- * @param string $name name the field to be declared.
- * @param string $field associative array with the name of the properties
- * of the field being declared as array indexes.
- * Currently, the types of supported field properties
- * are as follows:
- *
- * default
- * Date value to be used as default for this field.
- *
- * notnull
- * Boolean flag that indicates whether this field is
- * constrained to not be set to NULL.
- * @return string DBMS specific SQL code portion that should be used to
- * declare the specified field.
- * @access public
- */
- function getDateDeclaration($name, $field)
- {
- return("$name DATE".
- (isset($field['default']) ? " DEFAULT '".$field['default']."'" : '').
- (isset($field['notnull']) ? ' NOT NULL' : '')
- );
- }
-
- // }}}
- // {{{ getTimestampDeclaration()
-
- /**
- * Obtain DBMS specific SQL code portion needed to declare an timestamp
- * type field to be used in statements like CREATE TABLE.
- *
- * @param string $name name the field to be declared.
- * @param string $field associative array with the name of the properties
- * of the field being declared as array indexes.
- * Currently, the types of supported field
- * properties are as follows:
- *
- * default
- * Time stamp value to be used as default for this
- * field.
- *
- * notnull
- * Boolean flag that indicates whether this field is
- * constrained to not be set to NULL.
- * @return string DBMS specific SQL code portion that should be used to
- * declare the specified field.
- * @access public
- */
- function getTimestampDeclaration($name, $field)
- {
- return("$name DATETIME".
- (isset($field['default']) ? " DEFAULT '".$field['default']."'" : '').
- (isset($field['notnull']) ? ' NOT NULL' : '')
- );
- }
-
- // }}}
- // {{{ getTimeDeclaration()
-
- /**
- * Obtain DBMS specific SQL code portion needed to declare an time type
- * field to be used in statements like CREATE TABLE.
- *
- * @param string $name name the field to be declared.
- * @param string $field associative array with the name of the properties
- * of the field being declared as array indexes.
- * Currently, the types of supported field
- * properties are as follows:
- *
- * default
- * Time value to be used as default for this field.
- *
- * notnull
- * Boolean flag that indicates whether this field is
- * constrained to not be set to NULL.
- * @return string DBMS specific SQL code portion that should be used to
- * declare the specified field.
- * @access public
- */
- function getTimeDeclaration($name, $field)
- {
- return("$name TIME".
- (isset($field['default']) ? " DEFAULT '".$field['default']."'" : '').
- (isset($field['notnull']) ? ' NOT NULL' : '')
- );
- }
-
- // }}}
- // {{{ getFloatDeclaration()
-
- /**
- * Obtain DBMS specific SQL code portion needed to declare an float type
- * field to be used in statements like CREATE TABLE.
- *
- * @param string $name name the field to be declared.
- * @param string $field associative array with the name of the properties
- * of the field being declared as array indexes.
- * Currently, the types of supported field
- * properties are as follows:
- *
- * default
- * Integer value to be used as default for this
- * field.
- *
- * notnull
- * Boolean flag that indicates whether this field is
- * constrained to not be set to NULL.
- * @return string DBMS specific SQL code portion that should be used to
- * declare the specified field.
- * @access public
- */
- function getFloatDeclaration($name, $field)
- {
- if (isset($this->options['fixedfloat'])) {
- $this->fixed_float = $this->options['fixedfloat'];
- } else {
- if ($this->connection == 0) {
- // XXX needs more checking
- $this->connect();
- }
- }
- return("$name DOUBLE".
- ($this->fixed_float ?
- '('.($this->fixed_float + 2).','.$this->fixed_float.')' : '').
- (isset($field['default']) ?
- ' DEFAULT '.$this->getFloatValue($field['default']) : '').
- (isset($field['notnull']) ? ' NOT NULL' : '')
- );
- }
-
- // }}}
- // {{{ getDecimalDeclaration()
-
- /**
- * Obtain DBMS specific SQL code portion needed to declare an decimal type
- * field to be used in statements like CREATE TABLE.
- *
- * @param string $name name the field to be declared.
- * @param string $field associative array with the name of the properties
- * of the field being declared as array indexes.
- * Currently, the types of supported field
- * properties are as follows:
- *
- * default
- * Integer value to be used as default for this
- * field.
- *
- * notnull
- * Boolean flag that indicates whether this field is
- * constrained to not be set to NULL.
- * @return string DBMS specific SQL code portion that should be used to
- * declare the specified field.
- * @access public
- */
- function getDecimalDeclaration($name, $field)
- {
- return("$name BIGINT".
- (isset($field['default']) ?
- ' DEFAULT '.$this->getDecimalValue($field['default']) : '').
- (isset($field['notnull']) ? ' NOT NULL' : '')
- );
- }
-
- // }}}
- // {{{ getClobValue()
-
- /**
- * Convert a text value into a DBMS specific format that is suitable to
- * compose query statements.
- *
- * @param resource $prepared_query query handle from prepare()
- * @param $parameter
- * @param $clob
- * @return string text string that represents the given argument value in
- * a DBMS specific format.
- * @access public
- */
- function getClobValue($prepared_query, $parameter, $clob)
- {
- $value = "'";
- while(!$this->endOfLob($clob)) {
- if (MDB::isError($result = $this->readLob($clob, $data, $this->options['lob_buffer_length']))) {
- return($result);
- }
- $value .= $this->_quote($data);
- }
- $value .= "'";
- return($value);
- }
-
- // }}}
- // {{{ freeClobValue()
-
- /**
- * free a character large object
- *
- * @param resource $prepared_query query handle from prepare()
- * @param string $clob
- * @return MDB_OK
- * @access public
- */
- function freeClobValue($prepared_query, $clob)
- {
- unset($this->lobs[$clob]);
- return(MDB_OK);
- }
-
- // }}}
- // {{{ getBlobValue()
-
- /**
- * Convert a text value into a DBMS specific format that is suitable to
- * compose query statements.
- *
- * @param resource $prepared_query query handle from prepare()
- * @param $parameter
- * @param $blob
- * @return string text string that represents the given argument value in
- * a DBMS specific format.
- * @access public
- */
- function getBlobValue($prepared_query, $parameter, $blob)
- {
- $value = "'";
- while(!$this->endOfLob($blob)) {
- if (MDB::isError($result = $this->readLob($blob, $data, $this->options['lob_buffer_length']))) {
- return($result);
- }
- $value .= addslashes($data);
- }
- $value .= "'";
- return($value);
- }
-
- // }}}
- // {{{ freeBlobValue()
-
- /**
- * free a binary large object
- *
- * @param resource $prepared_query query handle from prepare()
- * @param string $blob
- * @return MDB_OK
- * @access public
- */
- function freeBlobValue($prepared_query, $blob)
- {
- unset($this->lobs[$blob]);
- return(MDB_OK);
- }
-
- // }}}
- // {{{ getFloatValue()
-
- /**
- * Convert a text value into a DBMS specific format that is suitable to
- * compose query statements.
- *
- * @param string $value text string value that is intended to be converted.
- * @return string text string that represents the given argument value in
- * a DBMS specific format.
- * @access public
- */
- function getFloatValue($value)
- {
- return(($value === NULL) ? 'NULL' : (float)$value);
- }
-
- // }}}
- // {{{ getDecimalValue()
-
- /**
- * Convert a text value into a DBMS specific format that is suitable to
- * compose query statements.
- *
- * @param string $value text string value that is intended to be converted.
- * @return string text string that represents the given argument value in
- * a DBMS specific format.
- * @access public
- */
- function getDecimalValue($value)
- {
- return(($value === NULL) ? 'NULL' : strval(round(doubleval($value)*$this->decimal_factor)));
- }
-
- // }}}
- // {{{ nextId()
-
- /**
- * returns the next free id of a sequence
- *
- * @param string $seq_name name of the sequence
- * @param boolean $ondemand when true the seqence is
- * automatic created, if it
- * not exists
- *
- * @return mixed MDB_Error or id
- * @access public
- */
- function nextId($seq_name, $ondemand = TRUE)
- {
- $sequence_name = $this->getSequenceName($seq_name);
- $this->expectError(MDB_ERROR_NOSUCHTABLE);
- $result = $this->query("INSERT INTO $sequence_name (sequence) VALUES (NULL)");
- $this->popExpect();
- if ($ondemand && MDB::isError($result) &&
- $result->getCode() == MDB_ERROR_NOSUCHTABLE)
- {
- // Since we are create the sequence on demand
- // we know the first id = 1 so initialize the
- // sequence at 2
- $result = $this->createSequence($seq_name, 2);
- if (MDB::isError($result)) {
- return($this->raiseError(MDB_ERROR, NULL, NULL,
- 'Next ID: on demand sequence could not be created'));
- } else {
- // First ID of a newly created sequence is 1
- return(1);
- }
- }
- $value = intval(mysql_insert_id($this->connection));
- $res = $this->query("DELETE FROM $sequence_name WHERE sequence < $value");
- if (MDB::isError($res)) {
- $this->warnings[] = 'Next ID: could not delete previous sequence table values';
- }
- return($value);
- }
-
-
- // }}}
- // {{{ currId()
-
- /**
- * returns the current id of a sequence
- *
- * @param string $seq_name name of the sequence
- * @return mixed MDB_Error or id
- * @access public
- */
- function currId($seq_name)
- {
- $sequence_name = $this->getSequenceName($seq_name);
- $result = $this->query("SELECT MAX(sequence) FROM $sequence_name", 'integer');
- if (MDB::isError($result)) {
- return($result);
- }
-
- return($this->fetchOne($result));
- }
-
- // }}}
- // {{{ fetchInto()
-
- /**
- * Fetch a row and insert the data into an existing array.
- *
- * @param resource $result result identifier
- * @param int $fetchmode how the array data should be indexed
- * @param int $rownum the row number to fetch
- * @return int data array on success, a MDB error on failure
- * @access public
- */
- function fetchInto($result, $fetchmode = MDB_FETCHMODE_DEFAULT, $rownum = NULL)
- {
- if ($rownum == NULL) {
- ++$this->highest_fetched_row[$result];
- } else {
- if (!@mysql_data_seek($result, $rownum)) {
- return(NULL);
- }
- $this->highest_fetched_row[$result] =
- max($this->highest_fetched_row[$result], $rownum);
- }
- if ($fetchmode == MDB_FETCHMODE_DEFAULT) {
- $fetchmode = $this->fetchmode;
- }
- if ($fetchmode & MDB_FETCHMODE_ASSOC) {
- $row = @mysql_fetch_assoc($result);
- if (is_array($row) && $this->options['optimize'] == 'portability') {
- $row = array_change_key_case($row, CASE_LOWER);
- }
- } else {
- $row = @mysql_fetch_row($result);
- }
- if (!$row) {
- if($this->options['autofree']) {
- $this->freeResult($result);
- }
- return(NULL);
- }
- if (isset($this->result_types[$result])) {
- $row = $this->convertResultRow($result, $row);
- }
- return($row);
- }
-
- // }}}
- // {{{ nextResult()
-
- /**
- * Move the internal mysql result pointer to the next available result
- * Currently not supported
- *
- * @param a valid result resource
- * @return true if a result is available otherwise return false
- * @access public
- */
- function nextResult($result)
- {
- return(FALSE);
- }
-
- // }}}
- // {{{ tableInfo()
-
- /**
- * returns meta data about the result set
- *
- * @param resource $result result identifier
- * @param mixed $mode depends on implementation
- * @return array an nested array, or a MDB error
- * @access public
- */
- function tableInfo($result, $mode = NULL) {
- $count = 0;
- $id = 0;
- $res = array();
-
- /*
- * depending on $mode, metadata returns the following values:
- *
- * - mode is false (default):
- * $result[]:
- * [0]['table'] table name
- * [0]['name'] field name
- * [0]['type'] field type
- * [0]['len'] field length
- * [0]['flags'] field flags
- *
- * - mode is MDB_TABLEINFO_ORDER
- * $result[]:
- * ['num_fields'] number of metadata records
- * [0]['table'] table name
- * [0]['name'] field name
- * [0]['type'] field type
- * [0]['len'] field length
- * [0]['flags'] field flags
- * ['order'][field name] index of field named "field name"
- * The last one is used, if you have a field name, but no index.
- * Test: if (isset($result['meta']['myfield'])) { ...
- *
- * - mode is MDB_TABLEINFO_ORDERTABLE
- * the same as above. but additionally
- * ['ordertable'][table name][field name] index of field
- * named 'field name'
- *
- * this is, because if you have fields from different
- * tables with the same field name * they override each
- * other with MDB_TABLEINFO_ORDER
- *
- * you can combine MDB_TABLEINFO_ORDER and
- * MDB_TABLEINFO_ORDERTABLE with MDB_TABLEINFO_ORDER |
- * MDB_TABLEINFO_ORDERTABLE * or with MDB_TABLEINFO_FULL
- */
-
- // if $result is a string, then we want information about a
- // table without a resultset
- if (is_string($result)) {
- $id = @mysql_list_fields($this->database_name,
- $result, $this->connection);
- if (empty($id)) {
- return($this->mysqlRaiseError());
- }
- } else { // else we want information about a resultset
- $id = $result;
- if (empty($id)) {
- return($this->mysqlRaiseError());
- }
- }
-
- $count = @mysql_num_fields($id);
-
- // made this IF due to performance (one if is faster than $count if's)
- if (empty($mode)) {
- for ($i = 0; $i<$count; $i++) {
- $res[$i]['table'] = @mysql_field_table ($id, $i);
- $res[$i]['name'] = @mysql_field_name ($id, $i);
- $res[$i]['type'] = @mysql_field_type ($id, $i);
- $res[$i]['len'] = @mysql_field_len ($id, $i);
- $res[$i]['flags'] = @mysql_field_flags ($id, $i);
- }
- } else { // full
- $res['num_fields'] = $count;
-
- for ($i = 0; $i<$count; $i++) {
- $res[$i]['table'] = @mysql_field_table ($id, $i);
- $res[$i]['name'] = @mysql_field_name ($id, $i);
- $res[$i]['type'] = @mysql_field_type ($id, $i);
- $res[$i]['len'] = @mysql_field_len ($id, $i);
- $res[$i]['flags'] = @mysql_field_flags ($id, $i);
- if ($mode & MDB_TABLEINFO_ORDER) {
- $res['order'][$res[$i]['name']] = $i;
- }
- if ($mode & MDB_TABLEINFO_ORDERTABLE) {
- $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
- }
- }
- }
-
- // free the result only if we were called on a table
- if (is_string($result)) {
- @mysql_free_result($id);
- }
- return($res);
- }
- }
-
- ?>